using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using System.Threading;
using System.Text.RegularExpressions;

namespace Rapier.Kodachi
{
    #region FTPClient Class
    public class KodachiFtp
    {
        const int BUFFER_SIZE = 2048;

        #region Events and Delegates
        /// <summary>
        /// <para>Event fired when data is sent during file upload.</para>
        /// </summary>
        public event FtpTransferDelegate OnFileUploadDataSent;
        /// <summary>
        /// <para>Event fired when data is received during file download.</para>
        /// </summary>
        public event FtpTransferDelegate OnFileDownloadDataReceived;

        public delegate void FtpTransferDelegate(object sender, FtpEventArgs e);
        #endregion

        #region Constructors
        public KodachiFtp(string hostName)
            :
           this(hostName, "", "") //e.g. anonymous FTP
        {
        }

        public KodachiFtp(string hostName, string userName, string password)
            :
           this(hostName, userName, password, 21) //most common port for ftp
        {
        }

        public KodachiFtp(string hostName, string userName, string password, int port)
            :
           this(hostName, userName, password, port, "/") //e.g. root directory
        {
        }

        public KodachiFtp(string hostName, string userName, string password, int port, string remotePath)
        {
            _HostName = hostName;
            _UserName = userName;
            _Password = password;
            _Port = port;
            _RemotePath = remotePath;
        }
        #endregion

        #region Properties
        private string _HostName;
        public string HostName
        {
            get
            {
                if (_HostName.StartsWith("ftp://"))
                    return _HostName;
                else
                    return "ftp://" + _HostName;
            }
            set { _HostName = value; }
        }

        private string _UserName;
        public string UserName
        {
            get { return _UserName; }
            set { _UserName = value; }
        }

        private string _Password;
        public string Password
        {
            get { return _Password; }
            set { _Password = value; }
        }

        private int _Port = 21;
        public int Port
        {
            get { return _Port; }
            set { _Port = value; }
        }

        private string _RemotePath = "/";
        public string RemotePath
        {
            get
            {
                if (_RemotePath.EndsWith("/"))
                    return _RemotePath;
                else
                    return _RemotePath + "/";
            }
            set
            {
                if (value.StartsWith("/") == false)
                {
                    _RemotePath = "/" + value;
                }
                else
                {
                    _RemotePath = value;
                }
            }
        }

        //These three (Local and Remote names) are used for the event args...
        private FileInfo _LocalFile;
        public FileInfo LocalFile
        {
            get { return _LocalFile; }
            set { _LocalFile = value; }
        }

        public string LocalFileName
        {
            get { return _LocalFile.Name; }
        }

        private string _RemoteFileName;
        public string RemoteFileName
        {
            get { return _RemoteFileName; }
            set { _RemoteFileName = value; }
        }
        //These two are used for the event args...


        #endregion

        #region Directory Functions
        public List<string> ListDirectory()
        {
            return ListDirectory(string.Empty);
        }
        public List<string> ListDirectory(string directory)
        {
            //return a simple list of filenames in directory
            FtpWebRequest ftp = GetRequest(GetDirectory(directory));
            //Set request to do simple list
            ftp.Method = WebRequestMethods.Ftp.ListDirectory;

            string str = GetStringResponse(ftp);
            //replace CRLF to CR, remove last instance
            str = str.Replace("\r", "").TrimEnd('\n');
            //split the string into a list
            List<string> result = new List<string>();
            result.AddRange(str.Split('\n'));
            return result;
        }

        public FtpDirectory ListDirectoryDetail()
        {
            return ListDirectoryDetail(string.Empty);
        }
        public FtpDirectory ListDirectoryDetail(string directory)
        {
            FtpWebRequest ftp = GetRequest(GetDirectory(directory));
            //Set request to do simple list
            ftp.Method = WebRequestMethods.Ftp.ListDirectoryDetails;

            string str = GetStringResponse(ftp);
            //replace CRLF to CR, remove last instance
            str = str.Replace("\r", "").TrimEnd('\n');
            //split the string into a list
            return new FtpDirectory(str, _LastDirectory);
        }
        #endregion

        #region Download
        public bool Download(string sourceFilename, string localFilename)
        {
            return Download(sourceFilename, localFilename, false); //Do NOT allow overwrite
        }
        public bool Download(string sourceFilename, string localFilename, bool permitOverwrite)
        {
            FileInfo fi = new FileInfo(localFilename);
            return Download(sourceFilename, fi, permitOverwrite);
        }

        #region Extra Versions of Download
        //'Version taking an FtpFileInfo
        public bool Download(FtpFileInfo file, string localFilename)
        {
            return Download(file.FullName, localFilename, false);
        }
        public bool Download(FtpFileInfo file, string localFilename, bool permitOverwrite)
        {
            return Download(file.FullName, localFilename, permitOverwrite);
        }

        //'Another version taking FtpFileInfo and FileInfo
        public bool Download(FtpFileInfo file, FileInfo localFI)
        {
            return Download(file.FullName, localFI, false);
        }
        public bool Download(FtpFileInfo file, FileInfo localFI, bool permitOverwrite)
        {
            return Download(file.FullName, localFI, permitOverwrite);
        }
        #endregion

        //Main Version of Download taking string/FileInfo
        public bool Download(string sourceFilename, FileInfo targetFI)
        {
            return Download(sourceFilename, targetFI, false);
        }
        public bool Download(string sourceFilename, FileInfo targetFI, bool permitOverwrite)
        {
            LocalFile = targetFI;
            RemoteFileName = sourceFilename;

            //1. check target
            if (targetFI.Exists && !permitOverwrite)
            {
                throw new ApplicationException("Target file already exists");
            }

            //2. check source
            string target = string.Empty;
            if (sourceFilename.Trim() == string.Empty)
                throw new ApplicationException("File not specified");
            else if (sourceFilename.Contains("/"))
            {
                //treat as a full path
                target = AdjustDir(sourceFilename);
            }
            else
            {
                //treat as filename only, use current directory
                target = RemotePath + sourceFilename;
            }

            string URI = HostName + target;



            //3. perform copy
            FtpWebRequest ftp = GetRequest(URI);
            long remoteFileLength = 0;
            try
            {
                remoteFileLength = GetFileSize(target);
            }
            catch
            {
                throw new ApplicationException("Could not find source file size!");
            }

            ftp.Method = WebRequestMethods.Ftp.DownloadFile;
            ftp.UseBinary = true;

            //open request and get response stream
            using (FtpWebResponse response = (FtpWebResponse)ftp.GetResponse())
            {
                using (Stream responseStream = response.GetResponseStream())
                {
                    //loop to read & write to file
                    using (FileStream fs = targetFI.OpenWrite())
                    {
                        try
                        {
                            byte[] buffer = new byte[BUFFER_SIZE];
                            int dataBytesRead = 0;
                            do
                            {
                                dataBytesRead = responseStream.Read(buffer, 0, buffer.Length);
                                fs.Write(buffer, 0, dataBytesRead);

                                if (OnFileDownloadDataReceived != null)
                                    OnFileDownloadDataReceived(this, new FtpEventArgs(HostName, Port, UserName, LocalFileName, RemoteFileName, fs.Position, remoteFileLength));

                            }
                            while (dataBytesRead != 0);
                            fs.Flush();
                        }
                        catch (Exception ex)
                        {
                            //catch error and delete file only partially downloaded
                            fs.Close();
                            //delete target file as it's incomplete
                            targetFI.Delete();
                            throw ex;
                        }
                    }

                }
            }

            return true;
        }
        #endregion

        #region Upload
        public bool UploadFile(string localFileName)
        {
            return UploadFile(localFileName, string.Empty);
        }

        public bool UploadFile(string localFileName, string remoteFileName)
        {
            if (File.Exists(localFileName) == false)
            {
                throw (new Exception("Local file " + localFileName + " not found"));
            }
            FileInfo localFile = new FileInfo(localFileName);
            return Upload(localFile, remoteFileName);

        }

        private bool Upload(FileInfo fileInfo, string targetFile)
        {
            bool retval = false;

            LocalFile = fileInfo;
            RemoteFileName = targetFile;

            #region Build Target Name
            string target = string.Empty;
            //Set up the target name
            if (targetFile.Trim().Length == 0)
            {
                //No target specified, use existing file name + remote dir
                target = RemotePath + fileInfo.Name;
            }
            else if (targetFile.Contains("/"))
            {
                //If contains / treat as a full path
                target = AdjustDir(targetFile);
            }
            else
            {
                //assume file name only, use current remote dir
                target = RemotePath + targetFile;
            }
            #endregion

            #region Check to make sure unit directory exists
            if (!DirectoryExists(RemotePath, true))
            {
                throw new ApplicationException("Remote directory is not valid, or permission is denied");
            }
            #endregion

            #region Set up FTP connection and state
            FtpState state = new FtpState();
            ManualResetEvent waitObject;

            //Set up the FTP connection
            string URI = HostName + target;
            FtpWebRequest ftp = GetRequest(URI);
            ftp.Method = WebRequestMethods.Ftp.UploadFile;
            ftp.UseBinary = true;
            ftp.ContentLength = fileInfo.Length;

            state.Request = ftp;
            state.FileName = fileInfo.Name;

            //Set event to wait on
            waitObject = state.OperationComplete;

            // Asynchronously get the stream for the file contents.
            ftp.BeginGetRequestStream(new AsyncCallback(EndGetStreamCallback), state);

            //Block on current thread until all operations are complete
            waitObject.WaitOne();

            if (state.OperationException != null)
            {
                retval = false;
                throw state.OperationException;
            }
            else
            {
                retval = true;
            }
            #endregion

            return retval;
        }

        private void EndGetStreamCallback(IAsyncResult ar)
        {
            FtpState state = (FtpState)ar.AsyncState;
            //Stream requestStream=null;

            #region Send the file
            byte[] buffer = new byte[BUFFER_SIZE];
            int dataBytesRead = 0;
            int count = 0;

            using (FileStream fs = File.OpenRead(LocalFile.FullName))
            {
                try
                {
                    using (Stream rs = state.Request.EndGetRequestStream(ar))
                    {
                        do
                        {
                            dataBytesRead = fs.Read(buffer, 0, BUFFER_SIZE);
                            rs.Write(buffer, 0, dataBytesRead);
                            count += dataBytesRead;

                            if (OnFileUploadDataSent != null)
                                OnFileUploadDataSent(this, new FtpEventArgs(HostName, Port, UserName, LocalFileName, RemoteFileName, fs.Position, fs.Length));

                        }
                        while (dataBytesRead != 0);

                        // Asynchronously get the response to the upload request.
                        state.Request.BeginGetResponse(new AsyncCallback(EndGetResponseCallback), state);
                    }
                }
                catch (Exception ex)
                {
                    state.OperationException = ex;
                    state.OperationComplete.Set();
                }
                finally
                {
                    fs.Close();
                }
            }
            #endregion
        }

        // The EndGetResponseCallback method 
        // completes a call to BeginGetResponse.
        private static void EndGetResponseCallback(IAsyncResult ar)
        {
            FtpState state = (FtpState)ar.AsyncState;
            FtpWebResponse response = null;
            try
            {
                response = (FtpWebResponse)state.Request.EndGetResponse(ar);
                response.Close();
                state.StatusDescription = response.StatusDescription;
                // Signal the main application thread that
                // the operation is complete.
                state.OperationComplete.Set();
            }
            // Return exceptions to the main application thread.
            catch (Exception e)
            {
                state.OperationException = e;
                state.OperationComplete.Set();
            }
        }
        #endregion

        #region Other Functions Rename/Delete etc
        public bool DeleteFile(string filename)
        {
            //Determine if file or full path
            string URI = HostName + GetFullPath(filename);

            FtpWebRequest ftp = GetRequest(URI);
            //Set request to delete
            ftp.Method = WebRequestMethods.Ftp.DeleteFile;
            try
            {
                //get response but ignore it
                GetStringResponse(ftp);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return true;
        }

        public bool FileExists(string filename)
        {
            //Try to obtain filesize: if we get error msg containing "550"
            //the file does not exist
            try
            {
                long size = GetFileSize(filename);
                return true;
            }
            catch (Exception ex)
            {
                //only handle expected not-found exception
                if (ex is System.Net.WebException)
                {
                    //file does not exist/no rights error = 550
                    if (ex.Message.Contains("550"))
                        return false;  //clear
                    else
                        throw ex;
                }
                else
                {
                    throw ex;
                }
            }
        }

        public long GetFileSize(string filename)
        {
            string path = string.Empty;
            if (filename.Contains("/"))
                path = AdjustDir(filename);
            else
                path = RemotePath + filename;

            string URI = HostName + path;
            FtpWebRequest ftp = GetRequest(URI);

            //Try to get info on file/dir?
            ftp.Method = WebRequestMethods.Ftp.GetFileSize;
            string tmp = GetStringResponse(ftp);

            return GetSize(ftp);
        }

        public bool RenameFile(string sourceFilename, string newName)
        {
            //Does file exist?
            string source = GetFullPath(sourceFilename);
            if (!FileExists(source))
            {
                throw new FileNotFoundException("File " + source + " not found");
            }

            //build target name, ensure it does not exist
            string target = GetFullPath(newName);
            if (target == source)
            {
                throw new ApplicationException("Source and target are the same");
            }
            else if (FileExists(target))
            {
                throw new ApplicationException("Target file " + target + " already exists");
            }

            //perform rename
            string URI = HostName + source;

            FtpWebRequest ftp = GetRequest(URI);
            //Set request to delete
            ftp.Method = WebRequestMethods.Ftp.Rename;
            ftp.RenameTo = target;
            try
            {
                //get response but ignore it
                GetStringResponse(ftp);
                return true;
            }
            catch
            {
                return false;
            }
        }

        public bool DirectoryExists(string dir)
        {
            return DirectoryExists(dir, false);
        }
        public bool DirectoryExists(string dir, bool createIfMissing)
        {
            try
            {
                //Find out if it is there...
                ListDirectory(dir);
                return true;
            }
            catch
            {
                //Not there or we don't have access...
                if (createIfMissing)
                {
                    if (CreateDirectory(dir))
                    {
                        //Successfully created!
                        return true;
                    }
                }
                //Not there or couldn't create
                return false;
            }
        }

        public bool CreateDirectory(string dirpath)
        {
            //perform create
            string URI = HostName + AdjustDir(dirpath);
            FtpWebRequest ftp = GetRequest(URI);
            //Set request to MkDir
            ftp.Method = WebRequestMethods.Ftp.MakeDirectory;
            try
            {
                //get response but ignore it
                GetStringResponse(ftp);
                return true;
            }
            catch
            {
                return false;
            }
        }

        public bool DeleteDirectory(string dirpath)
        {
            //perform remove
            string URI = HostName + AdjustDir(dirpath);
            FtpWebRequest ftp = GetRequest(URI);
            //Set request to RmDir
            ftp.Method = WebRequestMethods.Ftp.RemoveDirectory;
            try
            {
                //get response but ignore it
                GetStringResponse(ftp);
                return true;
            }
            catch
            {
                return false;
            }
        }
        #endregion

        #region Private Helper Methods

        //stores last retrieved/set directory
        private string _LastDirectory = string.Empty;

        private FtpWebRequest GetRequest(string URI)
        {
            UriBuilder myBuilder = new UriBuilder(URI);
            myBuilder.Port = Port;
            Uri myUri = myBuilder.Uri;

            FtpWebRequest newFtp = (FtpWebRequest)FtpWebRequest.Create(myUri);
            newFtp.Credentials = GetCredentials();
            newFtp.KeepAlive = false;
            return newFtp;
        }

        private ICredentials GetCredentials()
        {
            return new NetworkCredential(UserName, Password);
        }

        private string GetFullPath(string file)
        {
            if (file.Contains("/"))
                return AdjustDir(file);
            else
                return this.RemotePath + file;
        }

        private string AdjustDir(string fileName)
        {
            if (fileName.StartsWith("/"))
                return fileName;
            else
                return "/" + fileName;
        }

        private string GetDirectory()
        {
            return GetDirectory(string.Empty);
        }
        private string GetDirectory(string directory)
        {
            string URI = string.Empty;
            if (directory == string.Empty)
            {
                //build from current
                URI = HostName + RemotePath;
                _LastDirectory = RemotePath;
            }
            else
            {
                if (!directory.StartsWith("/"))
                {
                    throw new ApplicationException("Directory should start with /");
                }
                URI = HostName + directory;
                _LastDirectory = directory;
            }

            return URI;
        }

        private string GetStringResponse(FtpWebRequest ftp)
        {
            //Get the result, streaming to a string
            string result = string.Empty;
            using (FtpWebResponse response = (FtpWebResponse)ftp.GetResponse())
            {
                long size = response.ContentLength;
                using (Stream datastream = response.GetResponseStream())
                {
                    using (StreamReader sr = new StreamReader(datastream))
                    {
                        result = sr.ReadToEnd();
                    }
                }
            }
            return result;
        }

        private long GetSize(FtpWebRequest ftp)
        {
            long size = 0;
            using (FtpWebResponse response = (FtpWebResponse)ftp.GetResponse())
            {
                size = response.ContentLength;
            }
            return size;
        }
        #endregion

    }
    #endregion

    #region FTP State Class
    public class FtpState
    {
        private ManualResetEvent wait;
        private FtpWebRequest request;
        private string fileName;
        private Exception operationException = null;
        string status;

        public FtpState()
        {
            wait = new ManualResetEvent(false);
        }

        public ManualResetEvent OperationComplete
        {
            get { return wait; }
        }

        public FtpWebRequest Request
        {
            get { return request; }
            set { request = value; }
        }

        public string FileName
        {
            get { return fileName; }
            set { fileName = value; }
        }
        public Exception OperationException
        {
            get { return operationException; }
            set { operationException = value; }
        }
        public string StatusDescription
        {
            get { return status; }
            set { status = value; }
        }
    }
    #endregion

    #region FTP File Info Class
    public class FtpFileInfo
    {
        public enum DirectoryEntryTypes
        {
            File,
            Directory
        }

        //Stores extended info about FTP file
        #region Properties
        public string FullName
        {
            get
            {
                return Path + FileName;
            }
        }

        private string _FileName;
        public string FileName
        {
            get
            {
                return _FileName;
            }
        }

        private string _Path;
        public string Path
        {
            get
            {
                return _Path;
            }
        }

        private DirectoryEntryTypes _FileType;
        public DirectoryEntryTypes FileType
        {
            get
            {
                return _FileType;
            }
        }

        private long _Size;
        public long Size
        {
            get
            {
                return _Size;
            }
        }

        private DateTime _FileDateTime;
        public DateTime FileDateTime
        {
            get
            {
                return _FileDateTime;
            }
        }

        private string _Permission;
        public string Permission
        {
            get
            {
                return _Permission;
            }
        }

        public string Extension
        {
            get
            {
                int i = FileName.LastIndexOf(".");
                if (i >= 0 && i < FileName.Length - 1)
                {
                    return FileName.Substring(i + 1);
                }
                else
                {
                    return string.Empty;
                }
            }
        }

        public string NameOnly
        {
            get
            {
                int i = FileName.LastIndexOf(".");
                if (i > 0)
                    return FileName.Substring(0, i);
                else
                    return FileName;
            }
        }
        #endregion

        public FtpFileInfo(string line, string path)
        {
            Match m = GetMatchingRegex(line);
            if (m == null)
            {
                //failed
                throw new ApplicationException("Unable to parse line: " + line);
            }
            else
            {
                if (m.Groups["name"].Success)
                    _FileName = m.Groups["name"].Value;

                _Path = path;

                if (m.Groups["size"].Success)
                    _Size = Convert.ToInt64(m.Groups["size"].Value);

                if (m.Groups["permission"].Success)
                    _Permission = m.Groups["permission"].Value;

                string _dir = m.Groups["dir"].Value;
                if (_dir != string.Empty && _dir != "-")
                    _FileType = DirectoryEntryTypes.Directory;
                else
                    _FileType = DirectoryEntryTypes.File;

                try
                {
                    _FileDateTime = DateTime.Parse(m.Groups["timestamp"].Value);
                }
                catch
                {
                    _FileDateTime = DateTime.MinValue;
                }
            }
        }

        private Match GetMatchingRegex(string line)
        {
            Regex rx;
            Match m;
            for (int i = 0; i < _ParseFormats.Length - 1; i++)
            {
                rx = new Regex(_ParseFormats[i]);
                m = rx.Match(line);
                if (m.Success)
                    return m;
            }

            return null;
        }


        #region Regular expressions for parsing LIST results
        private string[] _ParseFormats = {
        @"(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\w+\s+\w+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{4})\s+(?<name>.+)",

        @"(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\d+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{4})\s+(?<name>.+)",

        @"(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\d+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{1,2}:\d{2})\s+(?<name>.+)",

        @"(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\w+\s+\w+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{1,2}:\d{2})\s+(?<name>.+)",

        @"(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})(\s+)(?<size>(\d+))(\s+)(?<ctbit>(\w+\s\w+))(\s+)(?<size2>(\d+))\s+(?<timestamp>\w+\s+\d+\s+\d{2}:\d{2})\s+(?<name>.+)",

        @"(?<timestamp>\d{2}\-\d{2}\-\d{2}\s+\d{2}:\d{2}[Aa|Pp][mM])\s+(?<dir>\<\w+\>){0,1}(?<size>\d+){0,1}\s+(?<name>.+)",

        @"(?<timestamp>\d{2}\-\d{2}\-\d{2}\s+\d{2}:\d{2}[Aa|Pp][mM])\s+(?<dir>\<\w+\>){0,1}\s+(?<name>.+)"};
        #endregion
    }
    #endregion

    #region FTP Directory Class
    public class FtpDirectory : List<FtpFileInfo>
    {
        #region Constructors
        public FtpDirectory()
        {
        }
        public FtpDirectory(string dir, string path)
        {
            //This loop is suspect...
            foreach (string line in dir.Replace("\r", "").Split('\n'))
            {
                if (line != string.Empty)
                {
                    Add(new FtpFileInfo(line, path));
                }
            }
        }
        #endregion

        public FtpDirectory GetFiles()
        {
            return GetFiles(string.Empty);
        }
        public FtpDirectory GetFiles(string ext)
        {
            return GetFileOrDir(FtpFileInfo.DirectoryEntryTypes.File, ext);
        }

        public FtpDirectory GetDirectories()
        {
            return GetFileOrDir(FtpFileInfo.DirectoryEntryTypes.Directory);
        }

        private FtpDirectory GetFileOrDir(FtpFileInfo.DirectoryEntryTypes type)
        {
            return GetFileOrDir(type, string.Empty);
        }
        private FtpDirectory GetFileOrDir(FtpFileInfo.DirectoryEntryTypes type, string ext)
        {
            FtpDirectory result = new FtpDirectory();
            foreach (FtpFileInfo fi in this)
            {
                if (fi.FileType == type)
                {
                    if (ext == string.Empty)
                        result.Add(fi);
                    else if (ext == fi.Extension)
                        result.Add(fi);
                }
            }
            return result;
        }

        public bool FileExists(string filename)
        {
            foreach (FtpFileInfo ftpFile in this)
            {
                if (ftpFile.FileName == filename)
                    return true;
            }
            return false;
        }

        private const char slash = '/';

        public string GetParentDirectory(string dir)
        {
            string temp = dir.TrimEnd(slash);
            int i = temp.LastIndexOf(slash);
            if (i > 0)
                return temp.Substring(0, i - 1);
            else
                throw new ApplicationException("No parent for root.");
        }
    }
    #endregion

    #region FTPEventArgs Class
    public class FtpEventArgs
    {
    #region Private Members
    private string szLocalFile, szRemoteFile;
    long lBytesTransferred, lTotalFileLength;
    #endregion

    #region Constructors
    /// <summary>
    /// <para>Constructor.</para>
    /// </summary>
    /// <param name="host">Connected host.</param>
    /// <param name="port">Connection port.</param>
    /// <param name="user">User, for whom session has been opened.</param>
    /// <param name="localfile">Name of the local file that is being transferred to/from.</param>
    /// <param name="remotefile">Name of the remote file that is being transferred from/to.</param>
    /// <param name="bytestransferred">Total bytes transferred so far.</param>
    /// <param name="totalfilelength">Length of the file that is being transferred.</param>
    public FtpEventArgs(string host, int port, string user, string localfile, string remotefile, long bytestransferred, long totalfilelength)
    {
        szLocalFile = localfile;
        szRemoteFile = remotefile;
        lBytesTransferred = bytestransferred;
        lTotalFileLength = totalfilelength;
    }
    /// <summary>
    /// <para>Constructor.</para>
    /// </summary>
    /// <param name="exception">Exception that has been raised during execution of method.</param>
    public FtpEventArgs(Exception exception) { }
    #endregion

    #region Properties
    /// <summary>
    /// <para>Name of the local file that is being transferred to/from.</para>
    /// </summary>
    public string LocalFile
    {
        get
        {
            return (szLocalFile);
        }
    }
    /// <summary>
    /// <para>Name of the remote file that is being transferred from/to.</para>
    /// </summary>
    public string RemoteFile
    {
        get
        {
            return (szRemoteFile);
        }
    }
    /// <summary>
    /// <para>Total bytes transferred so far.</para>
    /// </summary>
    public long BytesTransferred
    {
        get
        {
            return (lBytesTransferred);
        }
    }
    /// <summary>
    /// <para>Length of the file that is being transferred.</para>
    /// </summary>
    public long TotalFileLength
    {
        get
        {
            return (lTotalFileLength);
        }
    }
    #endregion
    }
    #endregion
}
